<template>
  <!-- v-click-outside 自定义指令 -->
  <div v-click-outside="handleClick" style="display: inline-block;">
    <input :value="formatDate"/>
    <div class="pannel" v-if="isVisible">
      <div class="pannel-nav">
        <span @click="prevYear">&lt;</span>
        <span style="margin-left: 6px;" @click="prevMonth">&lt;&lt;</span>
        <span>{{ time.year }}年</span>
        <span>{{ time.month+1 }}月</span>
        <span style="margin-right: 6px;" @click="nextMonth">&gt;&gt;</span>
        <span @click="nextYear">&gt;</span>
      </div>
      <div class="pannel-content">
        <div class="days">
          <span v-for="j in 7" :key="'_'+j" class="cell">
          {{ weekDays[j-1] }}
          </span>
          <div v-for="i in 6" :key="i">
            <!-- 6行7列 -->
          <span v-for="j in 7" :key="j" class="cell cell-day" 
          :class="[
  { notCurrentMonth: !isCurrentMonth(visibeDays[(i - 1) * 7 + (j - 1)]) },
  { today: isToday(visibeDays[(i - 1) * 7 + (j - 1)]) },
  {select: isSelect(visibeDays[(i - 1) * 7 + (j - 1)])}
]"
@click="chooseDate(visibeDays[(i - 1) * 7 + (j - 1)])"
>
            <!-- notCurrentMonth: !isCurrentMonth() 判断是不是当月不是当月置灰 -->
            <!-- today:isToday() 判断是不是今天 -->
          {{ visibeDays[(i-1)*7+(j-1)].getDate() }}
        </span>
        </div>
        </div>
      </div>
      <div class="pannel-footer">
        今天
      </div>
    </div>
  </div>
</template>

<script  lang="ts">

import { defineComponent,computed,ref,getCurrentInstance } from 'vue'
import * as utils from './utils'
export default defineComponent({
  name: 'datePicker',
  props: {
    modelValue: {
      type: Date,
      default: ()=>new Date()
    },
  },
  directives: {  // 挂载自定义指令
    clickOutside: {
      mounted(el, binding,vnode) {
    // 在页面挂载时处理
    const handle = (e) => {
      if (el.contains(e.target)) {
        // 判断绑定指令的容器中是否包含点击的元素
        binding.value(true); // 将值传给页面调用的handle方法
      } else {
        binding.value(false); // 将值传给页面调用的handle方法
      }
    };
    el.handle = handle; // 将方法放到指令容器上
    document.addEventListener("click", handle);
  },
  // 当指令与元素接触绑定并且父组件已卸载时，把事件清除，只调用一次
  unmounted(el) {
    document.removeEventListener("click", el.handle);
    delete el.handle;
  },
}
},
emits: ['update:modelValue'],
setup(props) {
    const { year,month } = utils.getYearMonthDay(props.modelValue)
    const time = ref({year,month})
    const isVisible = ref(false)
  const weekDays = ref(['日', '一', '二', '三', '四', '五', '六'])

  // const vClickOutside = {}  自定义指令setup用法 直接将clickOutside中的内容都进对象
  
    const { emit } =getCurrentInstance()
    const formatDate = computed(() => {  // 获取当前传入的日期
      let { year, month, day } = utils.getYearMonthDay(props.modelValue)
      return `${year}-${month+1}-${day}`
    })
    const visibeDays = computed(() => { 
      // 先获取当前是周几
      let { year, month } = utils.getYearMonthDay(utils.getDate(time.value.year,time.value.month,1))
      let currentFirsDay:any = utils.getDate(year, month, 1) // 获取当前月份的第一天
      let week = currentFirsDay.getDay() // 获取当前月第一天是周几
      let starDay = currentFirsDay - (week ==0 ? 7:week) * 60 * 60 * 1000 * 24 // 用当前月第一天减去当前是周几  获得当前日历开始的第一个日期
      let arr = []
      for (let i = 0; i < 42; i++) {  // 日历一页一般是42天
        arr.push(new Date(starDay+i*60*60*1000*24)) // 在每一天上加上一天时间便利获得当前日历 日期   第一次循环i=0 后面往后递增
      }
      return arr
    })
    const isCurrentMonth = (date) => { 
      // 是否为当前月
      let { year, month } = utils.getYearMonthDay(utils.getDate(time.value.year,time.value.month,1))  // 用户传过来的年月
      let { year: y, month: m } = utils.getYearMonthDay(date) // 日历表的年月
      return year == y && month == m  // 判断用户传过来的时间的年月是否等于日历表中的年月
    }
    const isToday = (date) => { // 判断是不是今天
      let { year, month,day } = utils.getYearMonthDay(new Date()) // 当前的年月日
      let { year: y, month: m, day: d } = utils.getYearMonthDay(date) // 日历表的年月日
      return year == y && month == m && day == d
    }
    const isSelect = (date) => { 
      // 是否选中
      let { year, month,day } = utils.getYearMonthDay(props.modelValue) // 当前选中的年月日
      let { year: y, month: m, day: d } = utils.getYearMonthDay(date) // 日历表的年月日
      return year == y && month == m && day == d
    }
    const chooseDate = (date) => { 
      // 选择日期
      const { year,month } = utils.getYearMonthDay(date)
      time.value.year = year
      time.value.month = month
      emit('update:modelValue', date)
      isVisible.value = false
    }
    const handleClick = (e) => { 
      isVisible.value = e // 直接将传过来的值赋值
  }
  const prevMonth = () => { 
    // 切换月份
    let d = utils.getDate(time.value.year, time.value.month, 1) // 获取当前年月的一个日期
    d.setMonth(d.getMonth() - 1) // 计算当前月减1
    time.value = utils.getYearMonthDay(d) // 获取年月
  }
  const nextMonth = () => { 
    // 切换月份
    let d = utils.getDate(time.value.year, time.value.month, 1) // 获取当前年月的一个日期
    d.setMonth(d.getMonth() + 1) // 计算当前月加1
    time.value = utils.getYearMonthDay(d) // 获取年月
  }
  const prevYear = () => { 
    // 切换年
    let d = utils.getDate(time.value.year, time.value.month, 1) // 获取当前年月的一个日期
    d.setFullYear(d.getFullYear() - 1) // 计算当前年减1
    time.value = utils.getYearMonthDay(d) // 获取年月
  }
  const nextYear = () => { 
    // 切换年
    let d = utils.getDate(time.value.year, time.value.month, 1) // 获取当前年月的一个日期
    d.setFullYear(d.getFullYear() + 1) // 计算当前年加1
    time.value = utils.getYearMonthDay(d) // 获取年月
  }
    return {formatDate,isVisible,handleClick,visibeDays,isCurrentMonth,isToday,weekDays,chooseDate,isSelect,time,prevMonth,nextMonth,prevYear,nextYear}
  },
})
</script>

<style scoped lang="scss">
.pannel{
  width: 32*7px;
  position: absolute;
  background: white;
  box-shadow: 2px 2px 2px pink,-2px -2px 2px pink;
  &-nav{
    height: 30px;
    display: flex;
    justify-content: space-around;
    span{
      cursor: pointer;
      user-select: none;
    }
  }
  &-content{
    .cell{
      display: inline-flex;
      justify-content: center;
      align-items: center;
    width: 32px;
    height: 32px;
    font-weight: bold;
    &.cell-day:hover,&.select{
      background: red;
      color: white;
      border-radius: 4px;
      cursor: pointer;
    }
    }
  }
  &-footer{
    height: 30px;
    text-align: center;
  }
}
.notCurrentMonth{
  color: gray;
}
.today{
  border: 1px solid red;
  box-sizing: border-box;
}
</style>